package cn.hftoday.db;

import java.sql.*;
import org.apache.log4j.*;
import cn.hftoday.util.*;

/**
 * Mysql database connection
 * @author lane.cn@gmail.com
 *
 */
public class MysqlConnection implements DatabaseConnection {
	private static final Logger LOG = Logger.getLogger(MysqlConnection.class);
	private String name = null;
	private String connectionString = null;
	private Connection connection = null;
	private Savepoint savepoint = null;

	public void beginTransaction() {
		try {
			if (!connection.getAutoCommit()) {
				LOG.error("cannot begin transaction");
				throw new RuntimeException("error.transaction.exist");
			}
			connection.setAutoCommit(false);
			savepoint = connection.setSavepoint();
		} 
		catch (Exception e) {
			LOG.error("cannot begin transaction", e);
			throw new RuntimeException("error.transaction.forbid", e);
		}
	}

	public void close() {
		try {
			this.connection.close();
		} 
		catch (Exception e) {
			LOG.error("cannot close mysql connection", e);
		}
	}

	public void commit() {
		try {
			if (connection.getAutoCommit()) {
				LOG.error("no transaction to commit");
				throw new RuntimeException("error.no.transaction");
			}
			this.connection.commit();
		} catch (Exception e) {
			LOG.error("cannot commit transaction");
			throw new RuntimeException("error.transaction.commit", e);
		} finally {
			try {
				connection.setAutoCommit(true);
			} catch (Exception e) {}
		}
	}

	public void rollback() {
		try {
			if (connection.getAutoCommit()) {
				LOG.error("no transaction to rollback");
				throw new RuntimeException("error.no.transaction");
			}
			connection.rollback(savepoint);
		} catch (Exception e) {
			LOG.error("cannot rollback transaction", e);
			throw new RuntimeException("error.transaction.rollback", e);
		} finally {
			try {
				connection.setAutoCommit(true);
			} catch (Exception e) {}
		}
	}

	public String getName() {
		return this.name;
	}

	public boolean isClosed() {
		try {
			if (this.connection == null || this.connection.isClosed()) {
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			return true;
		}
	}

	public void open() {
		String url = StringParser.getValue("url", this.connectionString);
		String uid = StringParser.getValue("uid", this.connectionString);
		String pwd = StringParser.getValue("pwd", this.connectionString);
		String encoding = StringParser.getValue("encoding", this.connectionString);
		url = url + "?user=" + uid + "&password=" + pwd + "&characterEncoding=" + encoding;
		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			connection = DriverManager.getConnection(url);
			connection.setAutoCommit(true);
		} catch (Exception e) {
			LOG.fatal("cannot connection to mysql, url is: " + url, e);
			throw new RuntimeException("error.dbconn.fail", e);
		}
	}

	public RecordSet select(String sql) {
		LOG.debug(sql);
		try {
			Statement st = this.connection.createStatement();
			ResultSet rs = st.executeQuery(sql);
			RecordSet ret = new RecordSet();
			ret.setResultSet(rs);
			rs.close();
			rs = null;
			st.close();
			st = null;
			return ret;
		} catch (Exception e) {
			LOG.error("error in select mysql database, sql", e);
			throw new RuntimeException("error.db.select", e);
		}
	}

	public void setConnectionString(String connectionString) {
		this.connectionString = connectionString;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int update(String sql) {
		String[] ary = StringParser.split(sql, ';', '\'');
		int count = 0;
		for (int i = 0; i < ary.length; i ++) {
			if (ary[i] != null && !ary[i].trim().equals("")) {
				LOG.debug(ary[i]);
				try {
					Statement st = this.connection.createStatement();
					count += st.executeUpdate(ary[i]);
				} catch (Exception e) {
					LOG.error("error in update mysql database, sql", e);
					throw new RuntimeException("error.db.update", e);
				}
			}
		}
		return count;
	}
}
